package loader

import (
	"time"

	"gitee.com/Luna-CY/Golang-Project-Template/internal/context"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/context/contextutil"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/errors"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/logger"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/runtime"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/util/timer"
	"github.com/spf13/viper"
)

func init() {
	// 添加对 json5 的支持
	viper.SupportedExts = append(viper.SupportedExts, "json5")
}

func LoadConfigFromFile(path string, dst any) errors.Error {
	if "" == path {
		path = "config"
	}

	// Load main config
	if err := loadConfig(path, "main", dst); nil != err {
		return err
	}

	// Load config for special environment
	var env = runtime.GetEnvironment()
	if err := loadConfig(path, env, dst); nil != err {
		return err
	}

	// Load custom config
	if err := loadConfig(path, "custom", dst); nil != err {
		return err
	}

	return nil
}

func StartAutoLoader(dst any) {
	go func() {
		for {
			timer.NewMinuteTicker(contextutil.NewContext(), func(ctx context.Context, ticker *time.Ticker, now time.Time) {
				if err := LoadConfigFromDb(dst); nil != err {
					logger.SugarLogger(logger.WithStack()).Errorf("ICL_ER.LCA_DB.445252 自动加载配置失败: %v", err)
				}
			})
		}
	}()
}

func loadConfig(path string, name string, dst any) errors.Error {
	var registry = viper.NewCodecRegistry()
	registry.RegisterCodec("json5", &Json5Coder{})

	var v = viper.NewWithOptions(viper.WithDecoderRegistry(registry))
	v.AddConfigPath(path)
	v.SetConfigName(name)

	if err := v.ReadInConfig(); nil != err {
		var configFileNotFoundError viper.ConfigFileNotFoundError

		if !errors.As(err, &configFileNotFoundError) {
			return errors.New(errors.ErrorTypeServerInternalError, "ICL_ER.LC_IG.440544", "读取配置文件失败: %v", err)
		}
	}

	if err := v.Unmarshal(&dst); nil != err {
		return errors.New(errors.ErrorTypeServerInternalError, "ICL_ER.LC_IG.490558", "解析配置文件失败: %v", err)
	}

	return nil
}

func LoadConfigFromDb(dst any) errors.Error {
	var cs = NewConfigurationService()
	configurations, err := cs.SafeGetAllConfiguration(contextutil.NewContext())
	if nil != err {
		return err.Relation(errors.ErrorServerInternalError("ICL_ER.LCFD_DB.590622", "加载数据库配置失败"))
	}

	if 0 != len(configurations) {
		for _, configuration := range configurations {
			viper.Set(*configuration.Key, *configuration.Val)
		}

		if err := viper.Unmarshal(&dst); nil != err {
			return errors.New(errors.ErrorTypeServerInternalError, "ICL_ER.LCFD_DB.680652", "解析配置文件失败: %v", err)
		}
	}

	return nil
}
